/**
 * Implements the stack data type using linked nodes based on 
 * LinkedIntStack.java by the same author.
 * 
 * @author          Maria Garcia de la Banda
 * @modified        Brendon Taylor (July 2009) - JavaDoc / Indentation / Style
 *                  Brendon Taylor (Feb 2010) - JavaDoc
 *                  Maria Garcia de la Banda (March 2011) - details
 * @since           11th March 2007
 * @input           none
 * @output          only for regression testing
 * @errorHandling   none
 * @knownBugs       none
 */

/*
 * Invariants: 
 *    (1) top points to the top element in the stack, or null if empty
 *    (2) each node N points to the node that was on top before pushing N
 */
package prac5;
public class LinkedFighterStack {   
    /** reference to the top node in the stack */
    private Node top;

    /**
     * Implements the node data type used in our linked stack.
     * 
     * @author   Maria Garcia de la Banda
     * @modified Brendon Taylor (July 2009) - JavaDoc / Indentation / Style
     *           Brendon Taylor (Feb 2010) - JavaDoc
     *           Maria Garcia de la Banda (March 2011) - details
     */
    private class Node { 
        /** data in the node */
        private Fighter item; 
        /** link to the successor node */
        private Node successor;

        /**
         * Creates a new node, with the input newItem as data and linked 
         * to the node newSuccessor.
         * 
         * @param  newItem to store in this node 
         * @param  newSuccessor refers to the successor node in the stack
         * @post   a node object is created with data newItem and linked 
         *         to newSuccessor
         * @complexity  best and worst case: O(1)
         */
        public Node(Fighter newItem, Node newSuccessor) { 
            item = newItem;
            successor = newSuccessor;
        }
    }

    /**
     * Creates an empty object of the class, i.e., an empty stack of Fighters
     * Since the stack is implemented with nodes, the size is not needed.
     * 
     * @post        an empty stack is created
     * @complexity  best and worst case: O(1)
     */
    public LinkedFighterStack() {
        top = null;
    }

    /**
     * Creates an empty object of the class, i.e., an empty stack of Fighters. 
     * The size is disregarded. This method is included to keep the same 
     * interface as the Stack implemented with arrays.
     * 
     * @param       size (ignored) 
     * @post        an empty stack is created
     * @complexity  best and worst case: O(1)
     */
    public LinkedFighterStack(Fighter size) {
	this();
    }

    /**
     * Determines whether the stack is empty.
     * 
     * @return      true if the stack is empty, false otherwise
     * @complexity  best and worst case: O(1)
     */
    public boolean isEmpty() {
        return (top == null);
    }

    /**
     * Determines whether the stack is full.
     * Since it is implemented with linked nodes, it will never be.
     * Method introduced for consistency with the stack implemented with arrays.
     * 
     * @return      false
     * @complexity  best and worst case: O(1)
     */
    public boolean isFull() {
        return false;
    } 

    /**
     * Resets the stack to an empty state.
     * 
     * @post        the stack is emptied
     * @complexity  best and worst case: O(1) 
     */
    public void reset() {
        top = null;
    }

    /**
     * Adds an element to the top of the stack. 
     * 
     * @param       newItem to be pushed onto the top of our stack
     * @post        the stack contains all previous items in the same
     *              relative position, plus the input item at the top.
     * @complexity  best and worst case: O(1) 
     */
    public void push(Fighter newItem) {
        top = new Node(newItem, top);
    }

    /**
     * Eliminates the top element from the stack and returns it,
     * making the element "under it" the new top. If the stack is empty, it
     * throws an exception.
     * 
     * @return      top element off stack
     * @throws      Exception thrown when stack is empty
     * @post        the stack contains all previous items in the same
     *              relative position, except the item that was at the top.
     * @complexity  best and worst case: O(1)
     */
    public Fighter pop() throws Exception {
        if (isEmpty())
                throw new Exception("Stack is empty");
        
        Fighter temp = top.item;
        top = top.successor;
        return temp;
    }

    /**
     * Returns the element that is at the top of the stack, 
     * if the stack is empty, it throws an exception.
     * 
     * @return      top element off stack
     * @throws      Exception thrown when stack is empty
     * @post        the stack is unchanged and has the returned item at top
     * @complexity  best and worst case: O(1) 
     */
    public Fighter top() throws Exception {
        if (this.isEmpty())
                throw new Exception("Stack is empty");
        
        return top.item;
    }

    /**
     * Return a copy of the contents.
     *
     * @return      clone of the stack
     * @complexity  best and worst case: O(N)
     */
    @Override
    public LinkedFighterStack clone() {
        LinkedFighterStack tempStack = new LinkedFighterStack();
        LinkedFighterStack cloneStack = new LinkedFighterStack();

        Node current = top;
        while (current != null) { 
                tempStack.push(current.item);
                current = current.successor;
        }

        current = tempStack.top;
        while (current != null) { 
                String className = current.item.getClass().getSimpleName();
                if (className.equals("Soldier"))
                        cloneStack.push(new Soldier());
                else if (className.equals("Archer"))
                        cloneStack.push(new Archer());
                else if (className.equals("Cavalry"))
                        cloneStack.push(new Cavalry());                 
                current = current.successor;
        }               

        return cloneStack;
    }

    /**
     * A string representation of the stack.
     * 
     * @return      a string representing the content of the stack
     * @post        every element of the stack appears in string format 
     *              starting from the top and separated by spaces
     * @complexity  best and worst case: Comp_Substring + O(count)*Comp_+O(N)
     *              (i.e., the complexity of substring plus that of O(N) 
     *               multiplied by that of + )
     */
    public String toString() {    
        String outString = "";
        Node current = top;

        while (current != null) { 
            outString += current.item + "\n";
            current = current.successor;
        }

        return outString;
    }

}